//reservation system class implementation
#include "reservationsystem.h"
#include <iostream>
#include <string>
using std::cout;
using std::cin;
using std::endl;
using namespace std;


//default data files
const char* reservationSystem::passengerFile = "passengers.csv";
const char* reservationSystem::flightFile = "flights.csv";
const char* reservationSystem::bookingFile = "bookings.csv";
const char* reservationSystem::cityFile = "cities.dat";

//default constructor
reservationSystem::reservationSystem()
{
	string line;
	string del = ",";
	vector<string> tokens;
	
	in.clear();
	in.open(cityFile);
	while(in.good()){ //parse city file
		getline(in,line);
		cities.push_back(line);
	}
	in.close();
	
	in.clear();
	in.open(passengerFile);
	while(in.good()){ //parse passenger file
		getline(in,line);
		tokens.clear();
		tokenize(line,tokens,del);

		//check if all fields are valid
		if(checkForValidPassengerData(tokens)){
			//create passenger object and insert into list
			//if name is > 50 characters, truncate
			passengers.push_back(passenger(tokens[0],tokens[1].substr(0,50),tokens[2],tokens[3]));
		}
	}
	in.close();

	in.clear();
	in.open(flightFile);
	while(in.good()){ //parse flight file
		getline(in,line);
		tokens.clear();
		tokenize(line,tokens,del);

		//check if all fields are valid
		if(checkForValidFlightData(tokens)){
			
			int flightNumber = atoi(tokens[0].c_str());
			unsigned int departureTime = atoi(tokens[1].c_str());
			unsigned int arrivalTime = atoi(tokens[2].c_str());
			bool cancel = (atoi(tokens[5].c_str()) != 0);
						
			vector<vector<bool> > matrix;
			vector<bool> row;
			for(int i = 6, j = 1; i < 86; ++i, ++j){ //recreate seating plan
				int value = atoi(tokens[i].c_str()); //value = 0 or 1
				row.push_back(value != 0); //add value to vector as bool
				if(j % 4 == 0){
					matrix.push_back(row);
					row.clear();
				}
			}

			//create flight object and insert into list
			all_Flights.push_back(flight(flightNumber,departureTime,arrivalTime,tokens[3],tokens[4],cancel,matrix));
		}
	}
	in.close();
	
	in.clear();
	in.open(bookingFile);
	while(in.good()){ //parse booking file
		getline(in,line);
		tokens.clear();
		tokenize(line,tokens,del);

		//check if all fields are valid
		if(checkForValidBookingData(tokens)){
			int bookingNum = atoi(tokens[0].c_str());
			int pIndex = getPassengerIndex(tokens[1]);
			passenger *p = &passengers[pIndex];
			int fIndex = getFlightIndex(atoi(tokens[2].c_str()));
			flight *f = &all_Flights[fIndex];
			bool cancel = (atoi(tokens[4].c_str()) != 0);
			
			//create booking object and insert into list
			bookings.push_back(booking(bookingNum,p,f,tokens[3],cancel));
		}
	}
	in.close();
};

//destructor
reservationSystem::~reservationSystem()
{
	out.clear();
	out.open(passengerFile);
	if(out.good()){ //write passenger file
		for(vector<passenger>::iterator j = passengers.begin(); j != passengers.end(); ++j){
			out << j->getPassportNumber() << ",";
			out << j->getName() << ",";
			out << j->getAddress() << ",";
			out << j->getPhoneNumber() << endl;
		}
	}
	out.close();

	out.clear();
	out.open(flightFile);
	if(out.good()){ //write flight file
		for(vector<flight>::iterator k = all_Flights.begin(); k != all_Flights.end(); ++k){
			out << k->getFlightNumber() << ",";
			out << k->getDepartureTime() << ",";
			out << k->getArrivalTime() << ",";
			out << k->getDepartureCity() << ",";
			out << k->getArrivalCity() << ",";
			out << k->is_Cancelled() << ",";

			vector<vector<bool> > seating = k->getSeatingPlan();
			for(vector<vector<bool> >::iterator l = seating.begin(); l != seating.end(); ++l){
				for(vector<bool>::iterator m = l->begin(); m != l->end(); ++m){
					out << *m;
					if(!(l == seating.end()-1 && m == l->end()-1)) out << ",";
				}
			}
			out << endl;
		}
	}
	out.close();
	
	out.clear();
	out.open(bookingFile);
	if(out.good()){ //write booking file
		for(vector<booking>::iterator n = bookings.begin(); n != bookings.end(); ++n){
			out << n->getBookingNumber() << ",";
			passenger p = *(n->getPassenger());
			out << p.getPassportNumber() << ",";
			out << n->getFlight()->getFlightNumber() << ",";
			out << n->getSeatNumber() << ",";
			out << n->is_Cancelled() << endl;
		}
	}
	out.close();
};

void reservationSystem::tokenize(const string& str, vector<string>& tokens, const string& delimiters)
{
	if(tokens.empty()){
		// Skip delimiters at beginning.
		string::size_type lastPos = str.find_first_not_of(delimiters, 0);
		// Find first "non-delimiter".
		string::size_type pos     = str.find_first_of(delimiters, lastPos);

		while (string::npos != pos || string::npos != lastPos)
		{
			// Found a token, add it to the vector.
			tokens.push_back(str.substr(lastPos, pos - lastPos));
			// Skip delimiters.  Note the "not_of"
			lastPos = str.find_first_not_of(delimiters, pos);
			// Find next "non-delimiter"
			pos = str.find_first_of(delimiters, lastPos);
		}
	}
};

bool reservationSystem::checkForValidPassengerData(vector<string>& v)
{
	if(v.size() != 4) return false; //row does not contain 4 fields
	
	if(!checkForValidPassportFormat(v[0])) return false;
	if(!checkForValidPhoneFormat(v[3])) return false;

	return true; //all fields are valid
};

bool reservationSystem::checkForValidFlightData(vector<string>& v)
{
	if(v.size() != 86) return false; //row does not contain 86 fields

	if(!isNumber(v[0])) return false; //flight number contains a character

	if(!isNumber(v[1])) return false; //invalid departure time

	if(!isNumber(v[2])) return false; //invalid arrival time

	if(!checkForValidCity(v[3])) return false; //invalid departure city

	if(!checkForValidCity(v[4])) return false; //invalid arrival city

	if(!(v[5].compare("0") == 0 || v[5].compare("1") == 0)) return false;
	
	for(int i = 6; i < 86; ++i){
		if(!(v[i].compare("0") == 0 || v[i].compare("1") == 0)) return false; //invalid matrix data
	}


	return true; //all fields are valid
};

bool reservationSystem::checkForValidBookingData(vector<string>& v)
{
	if(v.size() != 5) return false; //row does not contain 5 fields

	if(!isNumber(v[0])) return false; //booking number is not a number

	if(!checkForValidPassenger(v[1])) return false; //passenger does not exist
	
	if(!isNumber(v[2])) return false; //flight number is not a number
	if(!checkForValidFlight(atoi(v[2].c_str()))) return false; //flight does not exist

	string seat = v[3];
	if(seat.length() != 2) return false; //not a valid seat number;
	
	char c = seat[0];
	int col;
	switch(c){
		case 'A': col = 0; break;
		case 'B': col = 1; break;
		case 'C': col = 2; break;
		case 'D': col = 3; break;
			break;
		default: return false; //not a valid seat number;
	}

	string r = seat.substr(1);
	int row = atoi(r.c_str());

	if(row < 1 || row > 20) return false; //not a valid seat number;

	if(!(v[4].compare("0") == 0 || v[4].compare("1") == 0)) return false;

	return true; //all fields are valid
};

bool reservationSystem::isNumber(string& s){
	for(string::iterator i = s.begin(); i != s.end(); ++i){
		if(isdigit(*i) == 0) return false; //digit expected
	}

	return true;
};

bool reservationSystem::checkForValidCity(string& s){
	for(vector<string>::iterator i = cities.begin(); i != cities.end(); ++i){
		if(i->compare(s) == 0) return true;
	}

	return false;
};

bool reservationSystem::checkForValidFlight(int flightNum)
{
	for(vector<flight>::iterator i = all_Flights.begin(); i != all_Flights.end(); ++i){
		if(i->getFlightNumber() == flightNum) return true;
	}

	return false;
};

bool reservationSystem::checkForValidPassenger(string& s)
{
	for(vector<passenger>::iterator i = passengers.begin(); i != passengers.end(); ++i){
		if(i->getPassportNumber().compare(s) == 0) return true;
	}

	return false;
};

int reservationSystem::getPassengerIndex(string& p)
{
	for(int i = 0; i < int(passengers.size()); ++i){
		if(passengers[i].getPassportNumber().compare(p) == 0) return i;
	}

	return -1;
};

int reservationSystem::getFlightIndex(int flightNum){
	for(int i = 0; i < int(all_Flights.size()); ++i){
		if(all_Flights[i].getFlightNumber() == flightNum) return i;
	}

	return -1;
};

void reservationSystem::test()
{
	listCities();
	
	cout << "\nList of passengers" << endl;
	for(vector<passenger>::iterator j = passengers.begin(); j != passengers.end(); ++j){
		cout << "Passport Number: " << j->getPassportNumber() << endl;
		cout << "Name: " << j->getName() << endl;
		cout << "Address: " << j->getAddress() << endl;
		cout << "Phone: " << j->getPhoneNumber() << endl << endl;
	}

	listFlights();
	listBookings();
};

int reservationSystem::addPassenger(string passportNum, string n, string add, string phone)
{
	int size = passengers.size();
	passengers.push_back(passenger(passportNum,n.substr(0,50),add,phone));

	if(passengers.size() == size + 1) return 0; //success
	else return -1; //fail
};

int reservationSystem::scheduleFlight(time_t dTime, time_t aTime, string dCity, string aCity){
	int size = all_Flights.size();
	
	vector<vector<bool> > matrix;
	vector<bool> row;
	for(int i = 0; i < 20; ++i){
		row.clear();
		for(int j = 0; j < 4; ++j){
			row.push_back(false);
		}
		matrix.push_back(row);
	}

	int fNumber = size+1;
	all_Flights.push_back(flight(fNumber,dTime,aTime,dCity,aCity,false,matrix));

	if(all_Flights.size() == size + 1) return fNumber; //success
	else return -1; //fail
};

int reservationSystem::newBooking(string pass, int fNumber){
	if(!checkForValidPassenger(pass)) return -1; //fail
	if(!checkForValidFlight(fNumber)) return -1; //fail

	passenger* p = &passengers[getPassengerIndex(pass)];
	flight* f = &all_Flights[getFlightIndex(fNumber)];

	int size = bookings.size();
	bookings.push_back(booking(size+1,p,f,f->getSeat(),false));

    if(bookings.size() == size + 1){
        cout << "Passenger " << p->getPassportNumber() << " is booked on flight " << f->getFlightNumber() << endl;
		cout << "Booking number: " << bookings.back().getBookingNumber() << endl;
        cout << "Seat number: " << bookings.back().getSeatNumber() << endl;
        return 0; //success
    }
    
	else return -1; //fail
};

void reservationSystem::listFlightInformation(int fNumber)
{
	if(!checkForValidFlight(fNumber)) cout << "Invalid flight number" << endl;
	else{
		int f = getFlightIndex(fNumber);

		cout << "Flight Number: " << all_Flights[f].getFlightNumber() << endl;
		if(all_Flights[f].is_Cancelled()) cout << "Flight is cancelled" << endl << endl;
		else{
			time_t dTime = all_Flights[f].getDepartureTime();
			time_t aTime = all_Flights[f].getArrivalTime();
			char a[26], d[26];
			ctime_s(d,26,&dTime);
			ctime_s(a,26,&aTime);
			cout << "Departure Time: " << d;
			cout << "Arrival Time: " << a;
			cout << "Departure City: " << all_Flights[f].getDepartureCity() << endl;
			cout << "Arrival City: " << all_Flights[f].getArrivalCity() << endl;

			vector<vector<bool> > seating = all_Flights[f].getSeatingPlan();
			cout << "Seating plan" << endl;
			for(vector<vector<bool> >::iterator l = seating.begin(); l != seating.end(); ++l){
				for(vector<bool>::iterator m = l->begin(); m != l->end(); ++m){
					cout << *m;
				}
				cout << endl;
			}
			cout << endl;
		}
	}
};

void reservationSystem::listPassengerInformation(string passNumber)
{
	if(!checkForValidPassenger(passNumber)) cout << "Invalid passport number" << endl;
	else{
		int p = getPassengerIndex(passNumber);	
		
		cout << "Passport Number: " << passengers[p].getPassportNumber() << endl;
		cout << "Name: " << passengers[p].getName() << endl;
		cout << "Address: " << passengers[p].getAddress() << endl;
		cout << "Phone: " << passengers[p].getPhoneNumber() << endl << endl;
	}
};

int reservationSystem::cancelFlight(int fNumber)
{
	if(!checkForValidFlight(fNumber)){
		cout << "Invalid flight number" << endl;
		return -1; //fail
	}
	else{
		int f = getFlightIndex(fNumber);
		all_Flights[f].cancel();

		if(all_Flights[f].is_Cancelled()) return 0; //sucess
		else return -1; //fail
	}
};

bool reservationSystem::checkForValidBooking(int bNumber)
{
	for(vector<booking>::iterator i = bookings.begin(); i != bookings.end(); ++i){
		if(i->getBookingNumber() == bNumber) return true;
	}

	return false;
};

int reservationSystem::getBookingIndex(int bNumber)
{
	for(int i = 0; i < int(bookings.size()); ++i){
		if(bookings[i].getBookingNumber() == bNumber) return i;
	}

	return -1;
};

int reservationSystem::cancelBooking(int bNumber)
{
    if(!checkForValidBooking(bNumber)){
        cout << "Invalid booking number" << endl;
        return -1; //fail
    }
    else{
        int bIndex = getBookingIndex(bNumber);
		bookings[bIndex].cancel();
		return 0; //success
    }
};

int reservationSystem::modifyPassenger(string passNum, string n, string add, string phone)
{
	if(!checkForValidPassenger(passNum)){
		cout << "Invalid passenger" << endl;
		return -1; //fail
	}
	else{
		int p = getPassengerIndex(passNum);
		if(n.compare("") != 0) passengers[p].setName(n.substr(0,50));
		if(add.compare("") != 0) passengers[p].setAddress(add);
		if(phone.compare("") != 0) passengers[p].setPhoneNumber(phone);

		return 0; //success
	}
};

int reservationSystem::updateFlight(int flightNum, time_t dTime, time_t aTime, string dCity, string aCity)
{
	if(!checkForValidFlight(flightNum)){
		cout << "Invalid flight number" << endl;
		return -1; //fail
	}
	else{
		int f = getFlightIndex(flightNum);
		if(dTime != 0) all_Flights[f].setDepartureTime(dTime);
		if(aTime != 0) all_Flights[f].setArrivalTime(aTime);
		if(!dCity.empty()) all_Flights[f].setDepartureCity(dCity);
		if(!aCity.empty()) all_Flights[f].setArrivalCity(aCity);
		return 0; //success
	}
};

bool reservationSystem::checkForValidTimeFormat(string& s)
{
	//Format = DD/MM/YYYY 24HR:MIN
	if(s.size() != 16) return false;
	if(s[2] != '/' || s[5] != '/' || s[10] != ' ' || s[13] != ':') return false;

	string sday,smonth,syear,shour,smin;
	sday = s.substr(0,2);
	smonth = s.substr(3,2);
	syear = s.substr(6,4);
	shour = s.substr(11,2);
	smin = s.substr(14,2);

	if(!isNumber(sday) || !isNumber(smonth) || !isNumber(syear) || !isNumber(shour) || !isNumber(smin)) return false;
	int iday,imonth,iyear,ihour,imin;
	iday = atoi(sday.c_str());
	imonth = atoi(smonth.c_str());
	iyear = atoi(syear.c_str());
	ihour = atoi(shour.c_str());
	imin = atoi(smin.c_str());
	
	struct tm* currenttime;
	struct tm* comparetime;
	time_t rawtime,testtime;
	time(&rawtime);
	currenttime = localtime(&rawtime);
	comparetime = currenttime;
	int currentYear = currenttime->tm_year+1900;

	if(iyear < currentYear) return false;
	if(imonth < 1 || imonth > 12) return false;

	int upperDay;
	switch(imonth){
		case 4:
		case 6:
		case 9:
		case 11:
			upperDay = 30;
			break;
		case 2:
			upperDay = 28;
			break;
		default:
			upperDay = 31;
			break;
	}

	if(iday < 1 || iday > upperDay) return false;

	if(ihour < 0 || ihour > 23) return false;
	if(imin < 0 || imin > 59) return false;

	comparetime->tm_year = iyear-1900;
	comparetime->tm_mon = imonth-1;
	comparetime->tm_mday = iday;
	comparetime->tm_hour = ihour;
	comparetime->tm_min = imin;
	testtime = mktime(comparetime);

	if(testtime < rawtime) return false;

	return true;
};

time_t reservationSystem::getTimeObject(string& t){
	if(!checkForValidTimeFormat(t)) return 0; //fail

	string sday,smonth,syear,shour,smin;
	sday = t.substr(0,2);
	smonth = t.substr(3,2);
	syear = t.substr(6,4);
	shour = t.substr(11,2);
	smin = t.substr(14,2);
	
	int iday,imonth,iyear,ihour,imin;
	iday = atoi(sday.c_str());
	imonth = atoi(smonth.c_str());
	iyear = atoi(syear.c_str());
	ihour = atoi(shour.c_str());
	imin = atoi(smin.c_str());

	struct tm* tstruct;
	time_t rawtime, newtime;
	time(&rawtime);
	tstruct = localtime(&rawtime);

	tstruct->tm_year = iyear-1900;
	tstruct->tm_mon = imonth-1;
	tstruct->tm_mday = iday;
	tstruct->tm_hour = ihour;
	tstruct->tm_min = imin;

	newtime = mktime(tstruct);

	return newtime;
};

void reservationSystem::AirlineAgentMenu()
{
	string departureCity;
	string arrivalCity;
	string departureDate;
	string returnDate;
	string firstName;
	string lastName;
	string updateField;
	
	string agentAction;

	cout<<"*********************************************"<<endl;
	cout<<"Please select your type of action below:"<<endl;
	cout<< "(1) Create a new booking" <<endl;
	cout<< "(2) Update a booking" <<endl;
	cout<< "(3) Cancel a booking" <<endl;
	cout<< "(4) Query booking information" <<endl;
	cout<< "(5) List bookings for a given flight" <<endl;
	cout<< "(6) Create new passenger" <<endl;
	cout<< "(7) Update passenger information" <<endl;
	cout<< "(8) Back to main menu" <<endl;
	cout<< "(9) Quit" <<endl;
	cout<<"*********************************************"<<endl<<endl;;
	cout<<"Action Type: ";
	getline(cin,agentAction);

	
	if (agentAction.compare("1") == 0) //new booking
	{
		string sel;
		do{
		cout<<"Is this for an existing passenger? Press 'y' for yes or 'n' for no: ";
		getline(cin,sel);
		}while(!(sel.compare("y") == 0 || sel.compare("n") == 0));

		string passportNum;
		if(sel.compare("n") == 0){
			string name, add, phone;
			
			cout<<"Please enter the new passenger's passport number: ";
			getline(cin,passportNum);
			while(!checkForValidPassportFormat(passportNum)){
				cout<<"Please enter a valid passport number: ";
				getline(cin,passportNum);
			}

			cout<<"Please enter the new passenger's name: ";
			getline(cin,name);

			cout<<"Please enter the new passenger's address: ";
			getline(cin,add);

			cout<<"Please enter the new passenger's phone number: ";
			getline(cin,phone);
			while(!checkForValidPhoneFormat(phone)){
				cout<<"Please enter a valid phone number: ";
				getline(cin,phone);
			}

			int res = addPassenger(passportNum,name,add,phone);
			if(res == -1){
				cout << "Adding passenger failed!" << endl;
				AirlineAgentMenu();
			}
			else cout << "Passenger successfully created" << endl;
		}
		else{	
			cout<<"Please enter the passengers passport number: ";
			getline(cin,passportNum);
			while(!checkForValidPassenger(passportNum)){
				cout << "Please input a valid passport number: ";
				getline(cin,passportNum);
			}
			listPassengerInformation(passportNum);
			cout<<endl;
		}
		
		string view;
		cout <<"To view a list of cities, press y; if not, press any key" << endl;
		getline(cin,view);
		if(view.compare("y") == 0) listCities();

search:	cout<<"Please enter your Departure city: ";	
		getline(cin,departureCity);
		while(!checkForValidCity(departureCity)){
			cout<<"Please enter a valid Departure city: ";	
			getline(cin,departureCity);
		}

		cout<<"Please enter your Arrival city: ";	
		getline(cin,arrivalCity);
		while(!checkForValidCity(arrivalCity)){
			cout<<"Please enter a valid Arrival city: ";	
			getline(cin,arrivalCity);
		}
		
		string DT, AT;
		time_t tDT;

		cout<<"Enter Departure Day/Time (DD/MM/YYYY 24HR:MIN): " <<endl;
		getline(cin,DT);
		while(!checkForValidTimeFormat(DT)){
			cout << "Please input a valid departure Day/Time (DD/MM/YYYY 24HR:MIN): " << endl;
			getline(cin,DT);
		}
		
		tDT = getTimeObject(DT);
	
		int fNum = searchFlight(departureCity, arrivalCity, tDT);
		if(fNum != -1) //flight found
		{
			cout<<"Our System Found a Flight Based on Your Searching Criteria" << endl;
			string t;
			do
			{			
				cout<<"Press 'v' to view the flight details or 'q' to abort: ";
				getline(cin,t);

				if(t.compare("q") == 0)
				{
					cout << endl;
					AirlineAgentMenu();
					return;
				}

				if(t.compare("v") == 0)
				{
					listFlightInformation(fNum);	//output flight details

					string c;				
					do{
						cout << "Would you like to book this flight? (y/n): ";
						getline(cin,c);
					}while(!(c.compare("y") == 0 || c.compare("n") == 0));
					
					if(c.compare("y") == 0){
						int r = newBooking(passportNum,fNum);
						if(r == -1) cout << "Booking failed!" << endl;
						else cout << "Booking created successfully" << endl;
						cout << endl;

						string x;	
						do{
							cout << "Would you like to book a return flight as well? (y/n): ";
							getline(cin,x);
						}while(!(x.compare("y") == 0 || x.compare("n") == 0));

						if(x.compare("n") == 0){
							AirlineAgentMenu();
							return;
						}
						else{
returnsearch:				cout<<"Enter Return Day/Time (DD/MM/YYYY 24HR:MIN): " <<endl;
							getline(cin,DT);
							while(!checkForValidTimeFormat(DT)){
								cout << "Please input a valid return Day/Time (DD/MM/YYYY 24HR:MIN): " << endl;
								getline(cin,DT);
							}
							
							tDT = getTimeObject(DT);
						
							int fNum = searchFlight(arrivalCity, departureCity, tDT);
							if(fNum != -1){ //flight found
								cout<<"Our System Found a Return Flight Based on Your Searching Criteria" << endl;
								string t;
								do
								{			
									cout<<"Press 'v' to view the return flight details or 'q' to abort: ";
									getline(cin,t);

									if(t.compare("q") == 0)
									{
										cout << endl;
										AirlineAgentMenu();
										return;
									}

									if(t.compare("v") == 0)
									{
										listFlightInformation(fNum);	//output flight details

										string c;				
										do{
											cout << "Would you like to book this return flight? (y/n): ";
											getline(cin,c);
										}while(!(c.compare("y") == 0 || c.compare("n") == 0));
										
										if(c.compare("y") == 0){
											int r = newBooking(passportNum,fNum);
											if(r == -1) cout << "Booking failed!" << endl;
											else cout << "Booking created successfully" << endl;
											cout << endl;
										}
										else{
											string c;				
											do{
												cout << "Would you like to search for another return flight? (y/n): ";
												getline(cin,c);
											}while(!(c.compare("y") == 0 || c.compare("n") == 0));
											
											if(c.compare("y") == 0) goto returnsearch;
											else{
												cout << endl;
												AirlineAgentMenu();
												return;
											}
										}
									}
								}while(!(t.compare("v") == 0 || t.compare("q") == 0));
							}
							else{
								cout << "No return flight found based on your search criteria" << endl;
								string c;				
								do{
									cout << "Would you like to search for another return flight? (y/n): ";
									getline(cin,c);
								}while(!(c.compare("y") == 0 || c.compare("n") == 0));
								
								if(c.compare("y") == 0) goto returnsearch;
								else{
									cout << endl;
									AirlineAgentMenu();
									return;
								}
							}
						}
					}
					else{
						string c;				
						do{
							cout << "Would you like to search for another flight? (y/n): ";
							getline(cin,c);
						}while(!(c.compare("y") == 0 || c.compare("n") == 0));
						
						if(c.compare("y") == 0) goto search;
						else{
							cout << endl;
							AirlineAgentMenu();
							return;
						}
					}
				}

			}while(!(t.compare("v") == 0 || t.compare("q") == 0));
		}
		
		cout << "No flight found based on your search criteria" << endl;
		string c;				
		do{
			cout << "Would you like to search for another flight? (y/n): ";
			getline(cin,c);
		}while(!(c.compare("y") == 0 || c.compare("n") == 0));
		
		if(c.compare("y") == 0) goto search;
		else{
			cout << endl;
			AirlineAgentMenu();
			return;
		}


		AirlineAgentMenu();
	}		
	
	else if (agentAction.compare("2") == 0) //update booking
	{
		int BN;
		string sBN, passNum;

		cout<<endl;
		listBookings();

		cout << "Enter the booking number you wish to update: ";
		getline(cin,sBN);
		BN = atoi(sBN.c_str());
		while(!checkForValidBooking(BN) || bookings[getBookingIndex(BN)].is_Cancelled()){
			if (!checkForValidBooking(BN)) cout<<"Please enter a valid booking number: ";
			else if (bookings[getBookingIndex(BN)].is_Cancelled()) cout<<"Please enter a booking that is not cancelled: ";
			getline(cin,sBN);
			BN = atoi(sBN.c_str());
		}

		cout <<"Enter a new passport number: ";
		getline(cin,passNum);
		while(!(checkForValidPassportFormat(passNum) || passNum.empty())){
			cout << "Please input a valid passport number: ";
			getline(cin,passNum);
		}

		
		string d, departureCity, arrivalCity;;	
		int fNum = -1;

		do{
			cout << "Search for a new flight? (y/n): ";
			getline(cin,d);
		}while(!(d.compare("y") == 0 || d.compare("n") == 0));
		
		if(d.compare("y") == 0){
usearch:	cout<<"Please enter your Departure city: ";	
			getline(cin,departureCity);
			while(!checkForValidCity(departureCity)){
				cout<<"Please enter a valid Departure city: ";	
				getline(cin,departureCity);
			}

			cout<<"Please enter your Arrival city: ";	
			getline(cin,arrivalCity);
			while(!checkForValidCity(arrivalCity)){
				cout<<"Please enter a valid Arrival city: ";	
				getline(cin,arrivalCity);
			}
			
			string DT, AT;
			time_t tDT;

			cout<<"Enter Departure Day/Time (DD/MM/YYYY 24HR:MIN): " <<endl;
			getline(cin,DT);
			while(!checkForValidTimeFormat(DT)){
				cout << "Please input a valid departure Day/Time (DD/MM/YYYY 24HR:MIN): " << endl;
				getline(cin,DT);
			}
			
			tDT = getTimeObject(DT);
		
			fNum = searchFlight(departureCity, arrivalCity, tDT);
			if(fNum != -1) //flight found
			{
				cout<<"Our System Found a Flight Based on Your Searching Criteria" << endl;
				string t;
				do
				{			
					cout<<"Press 'v' to view the flight details or 'q' to abort: ";
					getline(cin,t);

					if(t.compare("q") == 0)
					{
						cout << endl;
						AirlineAgentMenu();
						return;
					}

					if(t.compare("v") == 0)
					{
						listFlightInformation(fNum);	//output flight details

						string c;				
						do{
							cout << "Would you like to book this flight? (y/n): ";
							getline(cin,c);
						}while(!(c.compare("y") == 0 || c.compare("n") == 0));
						
						if(c.compare("n") == 0){
							string c;				
							do{
								cout << "Would you like to search for another flight? (y/n): ";
								getline(cin,c);
							}while(!(c.compare("y") == 0 || c.compare("n") == 0));
							
							if(c.compare("y") == 0) goto usearch;
						}
					}
				}while(!(t.compare("v") == 0 || t.compare("q") == 0));
			}
			else{
				cout << "No flight found based on your search criteria" << endl;
				string c;				
				
				do{
					cout << "Would you like to search for another flight? (y/n): ";
					getline(cin,c);
				}while(!(c.compare("y") == 0 || c.compare("n") == 0));
				
				if(c.compare("y") == 0) goto usearch;
			}
		}


		int res = updateBooking(BN, passNum, fNum);
		if(res == -1) cout << "Update booking failed!" << endl;
		else cout << "Booking updated successfully" << endl << endl;
		listBookings();

		AirlineAgentMenu();
	}

	else if (agentAction.compare("3") == 0) //cancel booking
	{	
		int BN;
		string sBN;

		cout<<endl;
		listBookings();

		cout<<"Enter the booking number you wish to cancel: ";
		getline(cin,sBN);
		BN = atoi(sBN.c_str());
		while(!checkForValidBooking(BN)){
			cout<<"Please enter a valid booking number: ";
			getline(cin,sBN);
			BN = atoi(sBN.c_str());
		}

		int result = cancelBooking(BN);
		
		if(result == -1) cout << "Cancel booking failed!" << endl;
		else cout << "Booking cancelled successfully" << endl << endl;
		listBookings();

		AirlineAgentMenu();
	}

	else if (agentAction.compare("4") == 0) //query booking
	{
		string passNum;

		cout<<"Please enter the passengers passport number: ";
		getline(cin,passNum);
		while(!checkForValidPassenger(passNum)){
			cout << "Please input a valid passport number: ";
			getline(cin,passNum);
		}
		listPassengerInformation(passNum);
		listBookingsForPassenger(passNum);

		AirlineAgentMenu();
	}

	else if (agentAction.compare("5") == 0) //list bookings for a given flight
	{
		int FN;
		string sFN;
		
		cout<<"Pleas enter a Flight Number to search: ";
		getline(cin,sFN);
		FN = atoi(sFN.c_str());
		while(!checkForValidFlight(FN)){
			cout << "Please input a valid flight number: ";
			getline(cin,sFN);
			FN = atoi(sFN.c_str());
		}
		listFlightInformation(FN);
		listBookingsForFlight(FN);

		AirlineAgentMenu();
	}

	else if (agentAction.compare("6") == 0) //new passenger
	{
		string passportNum, name, add, phone;
		
		cout<<"Please enter the passenger's passport number: ";
		getline(cin,passportNum);
		while(!checkForValidPassportFormat(passportNum)){
			cout<<"Please enter a valid passport number: ";
			getline(cin,passportNum);
		}

		cout<<"Please enter the passenger's name: ";
		getline(cin,name);

		cout<<"Please enter the passenger's address: ";
		getline(cin,add);

		cout<<"Please enter the passenger's phone number: ";
		getline(cin,phone);
		while(!checkForValidPhoneFormat(phone)){
			cout<<"Please enter a valid phone number: ";
			getline(cin,phone);
		}

		int res = addPassenger(passportNum,name,add,phone);
		if(res == -1) cout << "Adding passenger failed!" << endl;
		else cout << "Passenger successfully created" << endl << endl;

		AirlineAgentMenu();
	}

	else if (agentAction.compare("7") == 0) //update passenger
	{
		cout<<"Please enter the passengers passport number: ";
		getline(cin,updateField);
		while(!checkForValidPassenger(updateField)){
			cout << "Please input a valid passport number: ";
			getline(cin,updateField);
		}
		listPassengerInformation(updateField);
		
		string passNum, name, add, phone;
		
		cout<<"Enter a new passport number: ";
		getline(cin,passNum);
		while(!(checkForValidPassportFormat(passNum) || passNum.empty())){
			cout << "Please input a valid passport number: ";
			getline(cin,passNum);
		}

		cout<<"Enter a new name: ";
		getline(cin,name);

		cout<<"Enter a new address: ";
		getline(cin,add);

		cout<<"Enter a new phone number: ";
		getline(cin,phone);
		while(!(checkForValidPhoneFormat(phone) || phone.empty())){
			cout<<"Please enter a valid phone number: ";
			getline(cin,phone);
		}

		int res;
		if(!passNum.empty()) res = modifyPassportNumber(updateField,passNum);
		else passNum = updateField;
		res = modifyPassenger(passNum,name,add,phone);

		if(res == -1) cout << "Modifying passenger information failed!" << endl;
		else{
			cout << "Passenger information updated successfully " << endl << endl;
			listPassengerInformation(passNum);
		}

		AirlineAgentMenu();
	}													// end if else statement

	else if(agentAction.compare("8") == 0) MainMenu();

	else if(agentAction.compare("9") == 0) return;
	
	else{
		cout<<"You have made an invalid selection"<<endl;
		AirlineAgentMenu();
	}
};

void reservationSystem::OperationsManagerMenu()
{
		string managerAction;

		cout<<"*********************************************"<<endl;
		cout<<"Please select your type of action below:"<<endl;
		cout<< "(1) Schedule a flight" <<endl;
		cout<< "(2) Update flight information" <<endl;
		cout<< "(3) Cancel a flight" <<endl;
		cout<< "(4) List information for specific flight" <<endl;
		cout<< "(5) List all flights" <<endl;
		cout<< "(6) Back to main menu" <<endl;
		cout<< "(7) Quit" <<endl;
		cout<<"*********************************************"<<endl<<endl;
		cout<<"Action Type: ";
		getline(cin,managerAction);

		if (managerAction.compare("1") == 0) //new flight
		{
		cout<<"You Have Selected to Schedule a New Flight"<<endl;

			//int FN;
			string DC,AC,DT,AT;
			time_t tDT, tAT;
		
			cout<<"Enter Departure Day/Time (DD/MM/YYYY 24HR:MIN): " <<endl;
			getline(cin,DT);
			while(!checkForValidTimeFormat(DT)){
				cout << "Please input a valid departure Day/Time (DD/MM/YYYY 24HR:MIN): " << endl;
				getline(cin,DT);
			}

			cout<<"Enter Arrival Day/Time (DD/MM/YYYY 24HR:MIN): " <<endl;
			getline(cin,AT);
			while(!checkForValidTimeFormat(AT)){
				cout << "Please input a valid arrival Day/Time (DD/MM/YYYY 24HR:MIN): " << endl;
				getline(cin,AT);
			}

			cout<<"Enter Departure City: ";
			getline(cin,DC);
			while(!checkForValidCity(DC)){
				cout<<"Please enter a valid Departure City: ";
				getline(cin,DC);
			}

			cout<<"Enter Arrival City: ";
			getline(cin,AC);
			while(!checkForValidCity(AC)){
				cout<<"Please enter a valid Arrival City: ";
				getline(cin,AC);
			}

			tDT = getTimeObject(DT);
			tAT = getTimeObject(AT);
			int fNum = scheduleFlight(tDT,tAT,DC,AC);
			if(fNum == -1) cout << "Flight creation failed!" << endl;
			else{
				cout << "Flight created successfully!" << endl;
				listFlightInformation(fNum);
			}

			OperationsManagerMenu();
		}

		else if (managerAction.compare("2") == 0) //update flight
		{
			int FN;
			string sFN, DT, AT, DC, AC;
			time_t tDT, tAT;
			
			cout<<"You Have Selected to Update Flight Information"<<endl;
			cout<<"What is the Flight Number you Wish to Update?: ";
			getline(cin,sFN);
			FN = atoi(sFN.c_str());
			while(!checkForValidFlight(FN)){
				cout << "Please input a valid flight number: ";
				getline(cin,sFN);
				FN = atoi(sFN.c_str());
			}
			listFlightInformation(FN);

			cout<<"New Departure Day/Time (DD/MM/YYYY 24HR:MIN): ";
			getline(cin,DT);
			while(!(checkForValidTimeFormat(DT) || DT.empty())){
				cout << "Please input a valid departure Day/Time (DD/MM/YYYY 24HR:MIN): " << endl;
				getline(cin,DT);
			}

			cout<<"New Arrival Day/Time (DD/MM/YYYY 24HR:MIN): ";
			getline(cin,AT);
			while(!(checkForValidTimeFormat(AT) || AT.empty())){
				cout << "Please input a valid arrival Day/Time (DD/MM/YYYY 24HR:MIN): " << endl;
				getline(cin,AT);
			}

			cout <<"New Deparature City:";
			getline(cin,DC);
			while(!(checkForValidCity(DC) || DC.empty())){
				cout <<"Please enter a valid deparature city: ";
				getline(cin,DC);
			}

			cout <<"New Arrival City:";
			getline(cin,AC);
			while(!(checkForValidCity(AC) || AC.empty())){
				cout <<"Please enter a valid arrival city: ";
				getline(cin,AC);
			}

			if(!DT.empty()) tDT = getTimeObject(DT);
			else tDT = 0;
			if(!AT.empty()) tAT = getTimeObject(AT);
			else tAT = 0;

			if(updateFlight(FN, tDT, tAT, DC, AC) == -1) cout << "Flight update failed" << endl;
			else{
				cout << "Flight update successful" << endl << endl;
				listFlightInformation(FN);
			}

			OperationsManagerMenu();
		}
		
		else if(managerAction.compare("3") == 0){ //cancel flight
			int FN;
			string sFN;
			
			cout<<"What is the Flight Number you wish to cancel: ";
			getline(cin,sFN);
			FN = atoi(sFN.c_str());
			while(!checkForValidFlight(FN)){
				cout << "Please input a valid flight number: ";
				getline(cin,sFN);
				FN = atoi(sFN.c_str());
			}
			
			int res = cancelFlight(FN);
			if (res == -1) cout << "Flight cancellation failed!" << endl;
			else{
				bool OK = true;
				int res;

				for(vector<booking>::iterator n = bookings.begin(); n != bookings.end(); ++n){
					int BN;
					if(n->getFlight()->getFlightNumber() == FN){
						BN = n->getBookingNumber();
						res = cancelBooking(BN);
						if(res == -1) OK = false;
					}
				}
				
				if(OK){
					cout << "Flight successfully cancelled" << endl;
					listFlights();
				}
				else cout << "Flight cancellation failed!" << endl;
			}
			
			OperationsManagerMenu();
		}

		else if(managerAction.compare("4") == 0){ //List information for specific flight
			int FN;
			string sFN;
			
			cout<<"Please enter a Flight Number: ";
			getline(cin,sFN);
			FN = atoi(sFN.c_str());
			while(!checkForValidFlight(FN)){
				cout << "Please input a valid flight number: " << endl;
				getline(cin,sFN);
				FN = atoi(sFN.c_str());
			}
			listFlightInformation(FN);

			OperationsManagerMenu();
		}

		else if(managerAction.compare("5") == 0){ //List all flights
			
			listFlights();
			OperationsManagerMenu();
		}

		else if(managerAction.compare("6") == 0) MainMenu(); //Back to main menu
		
		else if(managerAction.compare("7") == 0) return; //Exit
		
		else{ //Invalid
			cout<<"You have made an invalid selection"<<endl;
			OperationsManagerMenu();
		}
};

void reservationSystem::listCities()
{
	cout << "List of cities" << endl;
	for(vector<string>::iterator i = cities.begin(); i != cities.end(); ++i){
		cout << *i << endl;
	}
};

int reservationSystem::searchFlight(string dCity, string aCity, time_t day)
{
	for(vector<flight>::iterator i = all_Flights.begin(); i != all_Flights.end(); ++i){
		//compare departure city, departure day, arrival city, arrival day with parameters
		if(i->getDepartureCity().compare(dCity) == 0 && i->getArrivalCity().compare(aCity) == 0
			&& compareDate(day,i->getDepartureTime())){
			return i->getFlightNumber(); //return flight number
		}
	}

	return -1; //fail
};

bool reservationSystem::compareDate(time_t t1, time_t t2)
{
	struct tm* d1;
	struct tm* d2;
	vector<int> d3;
	d1 = localtime(&t1);
	d3.push_back(d1->tm_year);
	d3.push_back(d1->tm_mon);
	d3.push_back(d1->tm_mday);
	d3.push_back(d1->tm_hour);
	d3.push_back(d1->tm_min);
	d2 = localtime(&t2);

	if(d1->tm_year != d3[0]) return false; //years do not match
	if(d1->tm_mon != d3[1]) return false; //months do not match 
	if(d1->tm_mday != d3[2]) return false; //days do not match
	if(d1->tm_hour != d3[3]) return false; //days do not match
	if(d1->tm_min != d3[4]) return false; //days do not match

	return true;
};

int reservationSystem::modifyPassportNumber(string currentP, string newP)
{
    if(!checkForValidPassenger(currentP)){
        cout << "Invalid passport number" << endl;
        return -1; //fail
    }
    else{
        int p = getPassengerIndex(currentP);
        passengers[p].setPassportNumber(newP);
       
        cout << "New passport number: " << passengers[p].getPassportNumber() << endl;
        return 0;
    }
};

void reservationSystem::MainMenu()
{
	string userType;
	do{
		cout<<"*********************************************"<<endl;
		cout<<"Please select your type of user below:"<<endl;
		cout<< "(1) Airline Agent" <<endl;
		cout<< "(2) Operations Manager" <<endl;
		cout<< "(3) Quit" <<endl;
		cout<<"*********************************************"<<endl<<endl;
		cout<<"User Type: ";
		getline(cin,userType);
	}while (!((userType.compare("1") == 0) || (userType.compare("2") == 0) || (userType.compare("3") == 0)));

	if (userType.compare("1") == 0){
		cout<<"Hello Agent"<<endl;
		AirlineAgentMenu();
	}

	else if (userType.compare("2") == 0){
		cout<<"Hello Manager"<<endl;;
		OperationsManagerMenu();
	}
};

void reservationSystem::listBookings()
{
	cout << "List of bookings" << endl;
	for(vector<booking>::iterator n = bookings.begin(); n != bookings.end(); ++n){
		cout << "Booking number: " << n->getBookingNumber() << endl;

		if(!n->is_Cancelled()){
			cout << "Passenger: " << n->getPassenger()->getPassportNumber() << endl;
			cout << "Flight: " << n->getFlight()->getFlightNumber() << endl;
			cout << "Seat Number: " << n->getSeatNumber() << endl << endl;
		}
		else cout << "This booking is cancelled!" << endl << endl;
	}
};

void reservationSystem::listFlights()
{
	cout << "\nList of flights" << endl;
	for(vector<flight>::iterator k = all_Flights.begin(); k != all_Flights.end(); ++k){
		cout << "Flight Number: " << k->getFlightNumber() << endl;
		
		if(!k->is_Cancelled()){
			time_t dTime = k->getDepartureTime();
			time_t aTime = k->getArrivalTime();
			char a[26], d[26];
			ctime_s(d,26,&dTime);
			ctime_s(a,26,&aTime);
			cout << "Departure Time: " << d;
			cout << "Arrival Time: " << a;
			cout << "Departure City: " << k->getDepartureCity() << endl;
			cout << "Arrival City: " << k->getArrivalCity() << endl;

			vector<vector<bool> > seating = k->getSeatingPlan();
			cout << "Seating plan" << endl;
			for(vector<vector<bool> >::iterator l = seating.begin(); l != seating.end(); ++l){
				for(vector<bool>::iterator m = l->begin(); m != l->end(); ++m){
					cout << *m;
				}
				cout << endl;
			}
		}
		else cout << "This flight is cancelled!" << endl;
		cout << endl;
	}
};

bool reservationSystem::checkForValidPassportFormat(string pNum)
{
	if(pNum.length() != 11) return false; //passport number should be 1 letter + 10 digits
	if(isalpha(pNum[0]) == 0) return false; //first character is not a letter
	if(!isNumber(pNum.substr(1))) return false; //10 digits expected but found at least one character

	return true;
};

bool reservationSystem::checkForValidPhoneFormat(string phone){
	if(phone.length() != 10) return false; //phone number should be 10 digits
	if(!isNumber(phone)) return false; //10 digits expected but found at least one character

	return true;
};

int reservationSystem::updateBooking(int bookingNum, string pass, int flight)
{
	if(!checkForValidBooking(bookingNum)) return -1; //fail
	if(!checkForValidPassenger(pass) && !pass.empty()) return -1; //fail
	if(!checkForValidFlight(flight) && flight != -1) return -1; //fail

	
	int bIndex = getBookingIndex(bookingNum);

	if(!pass.empty()){
		int pIndex = getPassengerIndex(pass);
		bookings[bIndex].setPassenger(&passengers[pIndex]);
	}
	if(flight != -1){
		int fIndex = getFlightIndex(flight);
		bookings[bIndex].getFlight()->freeSeat(bookings[bIndex].getSeatNumber()); //free the seat on the original flight		
		bookings[bIndex].setFlight(&all_Flights[fIndex]);
		bookings[bIndex].setSeatNumber(bookings[bIndex].getFlight()->getSeat());
	}

	return 0;
};

bool reservationSystem::checkBookingsForFlight(int flightNum)
{
	bool res = false;
	for(vector<booking>::iterator n = bookings.begin(); n != bookings.end(); ++n){
		if(n->getFlight()->getFlightNumber() == flightNum){
			res = true;
			break;
		}
	}

	return res;
};

void reservationSystem::listBookingsForFlight(int flightNum)
{
	if(!checkBookingsForFlight(flightNum)) cout << "There are no bookings for this flight number" << endl;
	else{
		cout << "Bookings for flight number " << flightNum << endl;
		for(vector<booking>::iterator n = bookings.begin(); n != bookings.end(); ++n){
			if(n->getFlight()->getFlightNumber() == flightNum){
				cout << "Booking number: " << n->getBookingNumber() << endl;

				if(!n->is_Cancelled()){
					cout << "Passenger: " << n->getPassenger()->getPassportNumber() << endl;
					cout << "Flight: " << n->getFlight()->getFlightNumber() << endl;
					cout << "Seat Number: " << n->getSeatNumber() << endl << endl;
				}
				else cout << "This booking is cancelled!" << endl << endl;
			}
		}
	}
};

bool reservationSystem::checkBookingsForPassenger(string pass)
{
	bool res = false;
	for(vector<booking>::iterator n = bookings.begin(); n != bookings.end(); ++n){
		if(n->getPassenger()->getPassportNumber().compare(pass) == 0){
			res = true;
			break;
		}
	}

	return res;
};

void reservationSystem::listBookingsForPassenger(string pass)
{
	if(!checkBookingsForPassenger(pass)) cout << "There are no bookings for this passenger" << endl;
	else{
		cout << "Bookings for passenger " << pass << endl;
		for(vector<booking>::iterator n = bookings.begin(); n != bookings.end(); ++n){
			if(n->getPassenger()->getPassportNumber().compare(pass) == 0){
				cout << "Booking number: " << n->getBookingNumber() << endl;

				if(!n->is_Cancelled()){
					cout << "Passenger: " << n->getPassenger()->getPassportNumber() << endl;
					cout << "Flight: " << n->getFlight()->getFlightNumber() << endl;
					cout << "Seat Number: " << n->getSeatNumber() << endl << endl;
				}
				else cout << "This booking is cancelled!" << endl << endl;
			}
		}
	}
};
